#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <arpa/inet.h>
#include <sys/wait.h>
#include <sys/select.h>
#include <pthread.h>
#include "list.h"

extern char* local_hostname;
extern int last_installed;
extern int state;

//#define DEBUG 0 	//Debug off
#define DEBUG 1		//Debug on

#if DEBUG == 1
//Print debug info
#define WHERESTR  "[%d][%d][%d]: "
#define WHEREARG  get_hostnum(local_hostname),last_installed,state
#define DEBUGPRINT2(...)       fprintf(stderr, __VA_ARGS__)
#define DEBUGPRINT(_msg, ...)  DEBUGPRINT2(WHERESTR _msg , WHEREARG, __VA_ARGS__)


#else
//No debug
#define DEBUGPRINT(_msg, ...) 
#endif

#define STATE_LEADER_ELECTION 0
#define STATE_REG_LEADER 1
#define STATE_REG_NONLEADER 2


#define TITLE_CU "CLIENT_UPDATE"
#define TITLE_VC "VIEW_CHANGE"
#define TITLE_VC_PROOF "VIEW_CHANGE_PROOF"
#define TITLE_PREP "PREPARE"
#define TITLE_PREP_OK "PREP_OK"
#define TITLE_PROP "PROPOSAL"
#define TITLE_ACCEPT "ACCEPT"
#define TITLE_GOU "GOU"
#define TITLE_HOST_ID "HOST_ID"
#define TITLE_GH "GLOBAL_HISTORY"


#define CU 100
#define VC 101
#define VC_PROOF 102
#define PREP 103
#define PREP_OK 104
#define PROP 105
#define ACCEPT 106
#define GOU 107
#define HOST_ID 108

#define INT_SIZE 4

struct client_ts {
	int client_id;
	int timestamp;
	struct list_head list;
};

struct msg_client_update {
	int client_id;
	int server_id;
	int timestamp;
	char *update;
	struct list_head list;
};

struct cu_list {
	struct msg_client_update *cu;
	struct list_head list;
};

struct msg_view_change {
	int server_id;
	int attempted;
	struct list_head list;
};

struct msg_vc_proof {
	int server_id;
	int installed;
};

struct msg_proposal {
	int server_id;
	int view;
	int seq;
	char *update;
	struct list_head list;
};

struct msg_prepare {
	int server_id;
	int view;
	int local_aru;
};

struct msg_globally_ordered_update {
	int server_id;
	int seq;
	char *update;
	struct list_head list;
};

struct msg_prepare_ok {
	int server_id;
	int view;
	struct msg_proposal pl;
	struct msg_globally_ordered_update goul;
	struct list_head list;
};

struct msg_accept {
	int server_id;
	int view;
	int seq;
	struct list_head list;
};

struct global_history {
	int seq;
	struct msg_proposal *prop;
	struct msg_accept accepts;
	struct msg_globally_ordered_update *gou;
	struct list_head list;
};

struct host_entry {
	int id;
	char *host_name;
	struct list_head list;
	int socket;
};

struct update_entry {
	char *value;
	struct list_head list;
};

struct msg_client_update *create_client_update(int client, int server, int timestamp, char *update);
char *serialize_client_update(struct msg_client_update *cu);
struct msg_client_update *deserialize_client_update(char *cu);

struct msg_view_change *create_view_change(int server_id, int attempted);
char *serialize_view_change(struct msg_view_change *vc);
struct msg_view_change *deserialize_view_change(char *vc);

struct msg_vc_proof *create_vc_proof(int server_id, int installed);
char *serialize_vc_proof(struct msg_vc_proof *vc_proof);
struct msg_vc_proof *deserialize_vc_proof(char *vc_proof);

struct msg_prepare *create_prepare(int server_id, int view, int local_aru);
char *serialize_prepare(struct msg_prepare *prep);
struct msg_prepare *deserialize_prepare(char *prep);

struct msg_proposal *create_proposal(int server_id, int view, int seq, char *update);
char *serialize_proposal(struct msg_proposal *prop);
struct msg_proposal *deserialize_proposal(char* prop);


struct msg_accept *create_accept(int server_id, int view, int seq);
char *serialize_accept(struct msg_accept *accept);
struct msg_accept *deserialize_accept(char *accept);

struct msg_globally_ordered_update *create_gou(int server_id, int seq, char *update);
char *serialize_gou(struct msg_globally_ordered_update *gou);
struct msg_globally_ordered_update *deserialize_gou(char *gou);

struct msg_prepare_ok *create_prepare_ok(int server_id, int view);
char *serialize_prepare_ok(struct msg_prepare_ok *po);
struct msg_prepare_ok *deserialize_prepare_ok(char *po);

int get_message_type(char *msg);
int conflict(char *msg);
void update_data_structures(char *msg);

char* serialize_gh(struct global_history*);
struct global_history* deserialize_gh(char* ghstr);


//init data structures
void init_ds();


//Host list maintenance
void init_host_list();
struct host_entry *add_host(char *host_name, int sock);
struct host_entry *add_client(int id, int sock);
int get_host_id(char *host_name);
char *get_host_name(int id);
void set_host_socket(char* host_name, int sock);
int get_host_socket(char *host_name);
char* get_host_by_socket(int sock);
void remove_host(char *host_name);


//VC list access functions
void add_vc(struct msg_view_change *msg);
void clear_vc_list();

//prep_ok list access functions
void add_prep_ok(struct msg_prepare_ok *mg);
void clear_prep_ok_list();

//update queue access functions
void add_client_update(struct msg_client_update *cu);
void clear_update_queue();
int update_queue_empty();

//pending updates access functions
void add_pending_update(struct msg_client_update *cu);
void clear_pending_updates();
void add_to_pending_updates(struct msg_client_update *cu);


//Leader election functions
void shift_to_leader_election(int view);
int preinstall_ready(int view);
void shift_to_reg_non_leader();
void shift_to_reg_leader();

//last_executed and last_enqueued lists
void update_last_executed(int client_id, int timestamp);
void clear_last_executed();
void update_last_enqueued(int client_id, int timestamp);
void clear_last_enqueued();

//Prepare Phase
void shift_to_prepare_phase();

int view_prepared_ready(int view);

//Queue Updates
void remove_bound_updates_from_queue();
void enqueue_unbound_pending_updates();
int enqueue_update(struct msg_client_update *u);
struct client_ts* get_from_last_enqueued(struct msg_client_update *cu);
struct client_ts* get_from_last_executed(struct msg_client_update *cu);
struct client_ts* get_from_pending_updates(struct msg_client_update *cu);
struct msg_client_update* get_from_update_queue(struct msg_client_update *cu);
int in_update_queue(struct msg_client_update *cu);
struct msg_client_update* get_from_pending_updates_message(char* msg);

//Propose Phase
void send_proposal();
void execute_update(int seq);

//Global history functions
void add_proposal(struct msg_proposal *prop);
void add_gou(struct msg_globally_ordered_update *gou);
void add_accept(struct msg_accept *accept);
struct global_history *get_history_entry(int seq);
void clear_history();
int in_global_history(int seq);
char* get_global_history_proposal(int seq);
int globally_ordered_ready(int seq);
int advance_aru();


int client_update_handler(struct msg_client_update *cu);
char *host_id_response();


int get_hostnum(char* host);
int my_itoa(int val, char* buf);
int send_to_socket(int socket, char* msg);

void sync();
void restore();